#!/usr/bin/perl
use strict;
use warnings;

# see bottom of this file for instructons and IMPORTANT WARNINGS!
# ----------------------------------------------------------------------

my $rule = $ARGV[7];
die "\n\nFATAL: GL_REFEX_EXPR_ doesn't exist\n(your admin probably forgot the rc file change needed for this to work)\n\n"
  unless exists $ENV{ "GL_REFEX_EXPR_" . $rule };
my $res = $ENV{ "GL_REFEX_EXPR_" . $rule } || 0;
print "$ARGV[6] ($res)\n" if $res;

exit 0;

__END__

------------------------------------------------------------------------
IMPORTANT WARNINGS:
  * has not been tested heavily
      * SO PLEASE TEST YOUR SPECIFIC USE CASE THOROUGHLY!
      * read the NOTES section below
  * syntax and semantics are to be considered beta and may change as I find
    better use cases
------------------------------------------------------------------------

Refex expressions, like VREFs, are best used as additional "deny" rules, to
deny combinations that the normal ruleset cannot detect.

To enable this, uncomment 'refex-expr' in the ENABLE list in the rc file.

It allows you to say things like "don't allow users u3 and u4 to change the
Makefile in the master branch" (i.e., they can change any other file in
master, or the Makefile in any other branch, but not that specific combo).

    repo foo
        RW+                                 =   u1 u2   # line 1

        RW+ master                          =   u3 u4   # line 2
        RW+                                 =   u3 u4   # line 3
        RW+ VREF/NAME/Makefile              =   u3 u4   # line 4
        -   master and VREF/NAME/Makefile   =   u3 u4   # line 5

Line 5 is a "refex expression".  Here are the rules:

  * for each refex in the expression ("master" and "VREF/NAME/Makefile" in
    this example), a count is kept of the number of times the EXACT refex was
    matched and allowed in the *normal* rules (here, lines 2 and 4) during
    this push.

  * the expression is evaluated based on these counts.  0 is false, and
    any non-zero is true (see more examples later).  The truth value of the
    expression determines whether the refex expression matched.

    You can use any logical or arithmetic expression using refexes as operands
    and using these operators:

        not and or xor + - == -lt -gt -eq -le -ge -ne

    Parens are not allowed.  Precedence is as you might expect for those
    operators.  It's actually perl that is evaluating it (you can guess what
    the '-lt' etc., get translated to) so if in doubt, check 'man perlop'.

  * the refexes that form the terms of the expression (in this case, lines 2
    and 4) MUST come before the expression itself (i.e., line 5).

  * note the words "EXACT refex was matched" above.

    Let's say you add "u3" to line 1.  Then the refex expression in line 5
    would never match for u3.  This is because line 1 prevents line 2 from
    matching (being more general *and* appearing earlier), so the count for
    the "master" refex would be 0.  If "master" is 0 (false), then "master and
    <anything>" is also false.

    (Same thing is you swap lines 2 and 3; i.e., put the "RW+ = ..." before
    the "RW+ master = ...").

    Put another way, the terms in the refex expression are refexes, not refs.
    Merely pushing the master branch does not mean the count for "master"
    increases; it has to *match* on a line that has "master" as the refex.

Here are some more examples:

  * user u2 is allowed to push either 'doc/' or 'src/' but not both

        repo    foo
            RW+                         =   u1 u2 u3

            RW+ VREF/NAME/doc/                      =   u2
            RW+ VREF/NAME/src/                      =   u2
            -   VREF/NAME/doc/ and VREF/NAME/src/   =   u2

  * user u3 is allowed to push at most 2 files to conf/

        repo    foo
            RW+                         =   u1 u2 u3

            RW+ VREF/NAME/conf/         =   u3
            -   VREF/NAME/conf/ -gt 2   =   u3
